using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Runtime.Serialization;

namespace net.notdot.Attercop {
    public struct MessageAddressing {
        public readonly IPEndPoint From;
        public readonly IPEndPoint To;

        public MessageAddressing(IPEndPoint from, IPEndPoint to) {
            From = from;
            To = to;
        }
    }

    public enum PeerState {
        /// <summary>
        /// The peer is unknown - we have never received a HelloMessage or PingMessage from them. 
        /// </summary>
        /// <remarks>
        /// Since we've never heard of the peer before, we don't have their public key on file, and so we can't verify the validity
        /// of their message. We don't know if they actually sent the message, or if it's just someone masquerading as them.
        /// 
        /// Nearly all messages from Unknown peers should be ignored.
        /// </remarks>
        Unknown,

        /// <summary>
        /// The peer is known - we have received a HelloMessage or PingMessage from them, but have not completed a handshake.
        /// </summary>
        /// <remarks>
        /// We've heard of the peer, and the message validated correctly, but we haven't completed a handshake with them. The
        /// owner of this public key could still be lying about their endpoint, and messages from them could be replays of old
        /// messages, sent by a malicious peer.
        /// 
        /// Most messages from Known peers should be ignored.
        /// </remarks>
        Known,

        /// <summary>
        /// The peer is known and has been introduced to us.
        /// </summary>
        /// <remarks>
        /// This is the normal state for most peers. Since we know their public key, and we've completed a handshake with them,
        /// we know the message is sent by the peer that claims to have sent it, that it's not a replay attack, and that they
        /// really can accept replies on their return address.
        /// </remarks>
        Introduced
    }

    public abstract class Message {
        internal PeerState m_PeerState;

        internal MessageAddressing m_Addressing;

        public MessageAddressing Addressing
        {
            get
            {
                return m_Addressing;
            }
        }

        internal Peer m_Sender;

        public Peer Sender
        {
            get
            {
                return m_Sender;
            }
        }

        public readonly long SequenceNumber;

        public readonly DateTime ReceivedAt;

        public Message(MessageAddressing addressing) {
            m_Addressing = addressing;
            SequenceNumber = DateTime.Now.Ticks;
            ReceivedAt = DateTime.Now;
        }

        /// <summary>
        /// The state the sender of this message was in with respect to us 
        /// </summary>
        public PeerState PeerState {
            get {
                return m_PeerState;
            }
        }

        /// <summary>
        /// Splits this message into numPieces parts. Returns null if the message cannot be split.
        /// </summary>
        /// <param name="numPieces">The number of pieces to split this message into.</param>
        /// <returns>The array of messages resulting from the split, or null if this message cannot be split.</returns>
        public virtual Message[] Split(int numPieces)
        {
            return null;
        }

        public Message(MessageReader reader)
        {
            reader.BeginRegion();
            reader.ReadByte();  //Version number
            SequenceNumber = reader.ReadInt64();
            reader.EndRegion();
        }

        public virtual void Serialize(MessageWriter writer)
        {
            writer.BeginRegion();
            writer.Write((byte)0);    //Version number
            writer.Write(SequenceNumber);
            writer.EndRegion();
        }
    }
}
